import Anthropic from "@anthropic-ai/sdk"
import * as vscode from "vscode"

import { RooCodeEventName } from "@roo-code/types"
import { TelemetryService } from "@roo-code/telemetry"

import { Task } from "../task/Task"
import { formatResponse } from "../prompts/responses"
import { Package } from "../../shared/package"
import { BaseTool, ToolCallbacks } from "./BaseTool"
import type { ToolUse } from "../../shared/tools"
import { t } from "../../i18n"
import { getCommitRangeForNewCompletion } from "../checkpoints/kilocode/seeNewChanges" // kilocode_change

// kilocode_change start
async function getClineMessageOptions(
	task: Task,
): Promise<{ isNonInteractive?: boolean; metadata?: Record<string, unknown> }> {
	const commitRange = await getCommitRangeForNewCompletion(task)

	if (!commitRange) {
		return {}
	}

	return {
		metadata: {
			kiloCode: { commitRange },
		},
	}
}
// kilocode_change end

interface AttemptCompletionParams {
	result: string
	command?: string
}

export interface AttemptCompletionCallbacks extends ToolCallbacks {
	askFinishSubTaskApproval: () => Promise<boolean>
	toolDescription: () => string
}

export class AttemptCompletionTool extends BaseTool<"attempt_completion"> {
	readonly name = "attempt_completion" as const

	parseLegacy(params: Partial<Record<string, string>>): AttemptCompletionParams {
		return {
			result: params.result || "",
			command: params.command,
		}
	}

	async execute(params: AttemptCompletionParams, task: Task, callbacks: AttemptCompletionCallbacks): Promise<void> {
		const { result } = params
		const { handleError, pushToolResult, askFinishSubTaskApproval, toolDescription, toolProtocol } = callbacks

		// Prevent attempt_completion if any tool failed in the current turn
		if (task.didToolFailInCurrentTurn) {
			const errorMsg = t("common:errors.attempt_completion_tool_failed")

			await task.say("error", errorMsg)
			pushToolResult(formatResponse.toolError(errorMsg))
			return
		}

		const preventCompletionWithOpenTodos = vscode.workspace
			.getConfiguration(Package.name)
			.get<boolean>("preventCompletionWithOpenTodos", false)

		const hasIncompleteTodos = task.todoList && task.todoList.some((todo) => todo.status !== "completed")

		if (preventCompletionWithOpenTodos && hasIncompleteTodos) {
			task.consecutiveMistakeCount++
			task.recordToolError("attempt_completion")

			pushToolResult(
				formatResponse.toolError(
					"Cannot complete task while there are incomplete todos. Please finish all todos before attempting completion.",
				),
			)

			return
		}

		try {
			if (!result) {
				task.consecutiveMistakeCount++
				task.recordToolError("attempt_completion")
				pushToolResult(await task.sayAndCreateMissingParamError("attempt_completion", "result"))
				return
			}

			task.consecutiveMistakeCount = 0

			await task.say(
				"completion_result",
				result,
				undefined,
				false,
				// kilocode_change start
				undefined,
				undefined,
				await getClineMessageOptions(task),
				// kilocode_change end
			)
			TelemetryService.instance.captureTaskCompleted(task.taskId)
			task.emit(RooCodeEventName.TaskCompleted, task.taskId, task.getTokenUsage(), task.toolUsage)

			if (task.parentTask) {
				const didApprove = await askFinishSubTaskApproval()

				if (!didApprove) {
					pushToolResult(formatResponse.toolDenied())
					return
				}

				pushToolResult("")
				await task.providerRef.deref()?.finishSubTask(result)
				return
			}

			const { response, text, images } = await task.ask("completion_result", "", false)

			if (response === "yesButtonClicked") {
				return
			}

			// User provided feedback - push tool result to continue the conversation
			await task.say("user_feedback", text ?? "", images)

			const feedbackText = `The user has provided feedback on the results. Consider their input to continue the task, and then attempt completion again.\n<feedback>\n${text}\n</feedback>`
			pushToolResult(formatResponse.toolResult(feedbackText, images))
		} catch (error) {
			await handleError("inspecting site", error as Error)
		}
	}

	override async handlePartial(task: Task, block: ToolUse<"attempt_completion">): Promise<void> {
		const result: string | undefined = block.params.result
		const command: string | undefined = block.params.command

		const lastMessage = task.clineMessages.at(-1)

		if (command) {
			if (lastMessage && lastMessage.ask === "command") {
				await task
					.ask("command", this.removeClosingTag("command", command, block.partial), block.partial)
					.catch(() => {})
			} else {
				await task.say(
					"completion_result",
					this.removeClosingTag("result", result, block.partial),
					undefined,
					false,
					// kilocode_change start
					undefined,
					undefined,
					await getClineMessageOptions(task),
					// kilocode_change end
				)

				TelemetryService.instance.captureTaskCompleted(task.taskId)
				task.emit(RooCodeEventName.TaskCompleted, task.taskId, task.getTokenUsage(), task.toolUsage)

				await task
					.ask("command", this.removeClosingTag("command", command, block.partial), block.partial)
					.catch(() => {})
			}
		} else {
			await task.say(
				"completion_result",
				this.removeClosingTag("result", result, block.partial),
				undefined,
				block.partial,
				// kilocode_change start
				undefined,
				undefined,
				await getClineMessageOptions(task),
				// kilocode_change end
			)
		}
	}
}

export const attemptCompletionTool = new AttemptCompletionTool()
